package com.share.device.emqx.handler.impl;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.share.common.core.constant.DeviceConstants;
import com.share.common.core.utils.StringUtils;
import com.share.common.rabbit.constant.MqConst;
import com.share.common.rabbit.service.RabbitService;
import com.share.device.domain.Cabinet;
import com.share.device.domain.CabinetSlot;
import com.share.device.domain.PowerBank;
import com.share.device.domain.Station;
import com.share.device.emqx.annotation.YEmqx;
import com.share.device.emqx.constants.EmqxConstants;
import com.share.device.emqx.handler.MessageHandler;
import com.share.device.service.ICabinetService;
import com.share.device.service.ICabinetSlotService;
import com.share.device.service.IPowerBankService;
import com.share.device.service.IStationService;
import com.share.order.domain.EndOrderVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Date;
import java.util.concurrent.TimeUnit;

//业务场景具体实现类
//在柜机中插入充电宝
@Slf4j
@Component
@YEmqx(topic = EmqxConstants.TOPIC_POWERBANK_CONNECTED)
public class PowerBankPushHandler implements MessageHandler {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ICabinetService cabinetService;
    @Autowired
    private ICabinetSlotService cabinetSlotService;
    @Autowired
    private IPowerBankService powerBankService;
    @Autowired
    private IStationService stationService;
    @Autowired
    private RabbitService rabbitService;

    //插入充电宝后，柜机端发送mqtt消息，结束订单或管理员插入充电宝，更新相关数据
    @Override
    public void handleMessage(JSONObject message) {
        log.info("插入充电宝: {}", message.toJSONString());

        //1. 获取消息编号
        String messageNo = message.getString("mNo");

        //基于Redis setnx 分布式锁 实现幂等性，防止重发处理消息
        String key = "powerBank:connected:" + messageNo;
        Boolean isExist = redisTemplate.opsForValue().setIfAbsent(key, message.toJSONString(), 1, TimeUnit.HOURS);

        if (!isExist){
            log.info("重复请求: {}", message.toJSONString());
            return;
        }

        //2.获取相关数据
        String cabinetNo = message.getString("cNo"); //柜机编号
        String powerBankNo = message.getString("pNo"); //充电宝编号
        String slotNo = message.getString("sNo"); //插槽编号
        BigDecimal electricity = message.getBigDecimal("ety"); //当前电量

        //非空判断
        if (StringUtils.isEmpty(cabinetNo)
                || StringUtils.isEmpty(powerBankNo)
                || StringUtils.isEmpty(slotNo)
                || null == electricity) {
            log.info("mqtt消息有数据为空: {}", message.toJSONString());
            return;
        }

        //3.获取相应实体对象
        //获取柜机
        Cabinet cabinet = cabinetService.getByCabinetNo(cabinetNo);
        // 获取充电宝
        PowerBank powerBank = powerBankService.getByPowerBankNo(powerBankNo);
        // 获取插槽
        CabinetSlot cabinetSlot = cabinetSlotService.getBtSlotNo(cabinet.getId(), slotNo);

        //4.更新充电宝电量和状态
        powerBank.setElectricity(electricity);
        //根据充电宝当前电量判断是否满足可用的最低值 设置状态
        if (electricity.subtract(DeviceConstants.ELECTRICITY_MIN).doubleValue() >= 0) {
            //可以借用
            powerBank.setStatus("1");
        } else {
            //充电中
            powerBank.setStatus("3");
        }
        powerBankService.updateById(powerBank);

        //更新插槽状态
        cabinetSlot.setPowerBankId(powerBank.getId()); //插入充电宝后，绑定充电宝id
        cabinetSlot.setStatus("1"); //状态1 该插槽有充电宝
        cabinetSlot.setUpdateTime(new Date());
        cabinetSlotService.updateById(cabinetSlot);

        //更新柜机信息
        int freeSlots = cabinet.getFreeSlots() - 1; //更新柜机空闲插槽数-1
        cabinet.setFreeSlots(freeSlots);
        int usedSlots = cabinet.getUsedSlots() + 1; //更新已使用插槽数+1
        cabinet.setUsedSlots(usedSlots);

        //如果新插入的充电宝可以借用，更新可用充电宝数+1
        if (powerBank.getStatus().equals("1")) {
            int availableNum = cabinet.getAvailableNum() + 1;
            cabinet.setAvailableNum(availableNum);
        }
        cabinet.setUpdateTime(new Date());

        cabinetService.updateById(cabinet);

        //获取站点对象
        LambdaQueryWrapper<Station> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Station::getCabinetId,cabinet.getId());
        Station station = stationService.getOne(wrapper);

        //封装结束订单数据VO对象
        EndOrderVo endOrderVo = new EndOrderVo();
        endOrderVo.setMessageNo(messageNo); //消息编号
        endOrderVo.setEndTime(new Date()); //订单结束时间
        endOrderVo.setEndCabinetNo(cabinetNo); //归还柜机编号
        endOrderVo.setEndStationId(station.getId()); //归还站点id
        endOrderVo.setEndStationName(station.getName()); //站点名
        endOrderVo.setPowerBankNo(powerBankNo); //充电宝编号

        //发送消息到mq，通知订单模块 结束相应订单
        String endOrderMsg = JSONObject.toJSONString(endOrderVo);
        rabbitService.sendMessage(MqConst.EXCHANGE_ORDER,MqConst.ROUTING_END_ORDER,endOrderMsg);
    }

}
